﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using PServiceBus.Core.Runtime.Extensions;

namespace PServiceBus.Redis {
    public class RedisStore<TObject> : RedisCollection<TObject> where TObject : class {

        public override IEnumerator<TObject> GetObjects() {
            var client = GetConnection(READ_ONLY_KEY);
            var values = client.HGetAll(Key);

            for (var i = 0; i < values.Length; i += 2) {
                var value = values[i + 1];
                yield return value.Deserialize<TObject>();
            }
        }

        public override bool Add(IEnumerable<TObject> list) {
            var success = false;
            Query(client =>
            {
                var count = list.Count();
                if (count > 0) {
                    var index = 0;
                    var keys = new byte[count][];
                    var values = new byte[count][];
                    foreach (var obj in list) {
                        keys[index] = GetID(obj);
                        values[index] = obj.Serialize();
                        index++;
                    }
                    client.HMSet(Key, keys, values);
                }
                success = true;
            });
            return success;
        }

        public override bool Add(TObject obj) {
            var success = false;
            Query(client =>
            {
                client.HSet(Key, GetID(obj), obj.Serialize());
                success = true;
            });
            return success;
        }

        public override bool Delete(IEnumerable<Func<TObject, bool>> conditions) {
            var objs = this.Where(d => d != null && conditions.Any(c => c(d))).ToList();
            return Delete(objs);
        }

        public override bool Delete(IEnumerable<TObject> list) {
            return Query<bool>(client =>
            {
                foreach (var obj in list)
                    client.HDel(Key, GetID(obj));
                return true;
            });
        }

        public override bool Delete(Func<TObject, bool> condition) {
            var objs = this.Where(d => d != null && condition(d));
            return Delete(objs);
        }

        public override bool Delete(TObject obj) {
            return Query(client =>
            {
                var success = client.HDel(Key, GetID(obj)) == 1;
                return success;
            });
        }

        public override bool Exists(Func<TObject, bool> condition) {
            return Get(condition) != null;
        }

        public override bool Exists(TObject obj) {
            return Query(client => client.HExists(Key, GetID(obj)) == 1);
        }

        public override TObject Get(Func<TObject, bool> condition) {
            return this.FirstOrDefault(d => d != null && condition(d));
        }

        public override TObject Get(Guid id) {
            return Query(client =>
            {
                var data = client.HGet(Key, id.ToByteArray());
                return data != null ? data.Deserialize<TObject>() : null;
            });
        }

        public override bool Refresh(TObject obj) {
            return Add(obj);
        }
    }
}
